using System;
using System.Collections.Generic;
using System.Collections;

namespace Com.ContentRendering.Api.DataEngine.Handler.Self
{
    /// <summary/>
    internal class KeyedCollectionSelfHandler : AbstractSelfHandler
    {
        /// <summary/>
        internal KeyedCollectionSelfHandler(
            ReflectionCache reflectionCache,
            object value)
            : base(
            reflectionCache,
            value) { }

        /// <summary/>
        internal override IEnumerator<object> Parse()
        {
            Type type = base._value.GetType();

            // does the property not exist
            if (base._reflectionCache.IsDictionaryFlagCached(type))
            {
                return base._successor.Parse();
            }

            bool hashTable = typeof(Hashtable).IsAssignableFrom(type);
            bool dictionary = KeyedCollectionSelfHandler.IsDictionary(type);

            // add the object to the cache ... doesn't matter if the property info is null
            base._reflectionCache.AddDictionaryFlag(
                type,
                hashTable || dictionary);

            // don't handle the dictionary or hashtable types ... always allow the indexer to be called
            if (!hashTable && !dictionary)
            {
                return base._successor.Parse();
            }

            List<object> parsedValues = new List<object>();

            // append the single item to the list
            parsedValues.Add(this._value);

            return parsedValues.GetEnumerator();        
        }

        /// <summary/>
        private static bool IsDictionary(Type type)
        {
            // if the type is not generic then move on cause its not a dictionary
            if (!type.IsGenericType)
            {
                return false;
            }

            Type[] arguments = type.GetGenericArguments();

            // if the type does not support two generic parameters then move on cause its not a dictionary
            if (arguments.Length != Constant.LENGTH_DICTIONARY_ARGUMENTS)
            {
                return false;
            }

            // build the matching dictionary type
            Type genericType = typeof(Dictionary<,>);
            Type dictionaryType = genericType.MakeGenericType(arguments);

            // if this is a dictionary type then handle it
            if (!dictionaryType.IsAssignableFrom(type))
            {
                return false;
            }

            return true;
        }
    }
}

